package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"sync"
	"syscall"
	"time"
)

func main() {
	kv := NewKV(time.Second * 3)
	kv.Open("mine")
	kv.Set("1", "123")
	time.Sleep(time.Second * 5)
}

func NewKV(Ds time.Duration) KV {
	if Ds <= 0 {
		Ds = time.Second * 30
	}

	return &MineKV{
		Ds:   Ds,
		data: make(map[string]string),
	}
}

type KV interface {
	Open(fn string)
	Get(k string) string
	Set(k, v string)
}

type MineKV struct {
	// 备份文件名
	cacheFile string
	// 读写锁
	rw sync.RWMutex
	// 缓存数据
	data map[string]string
	// 持久化间隔时间(秒)
	Ds time.Duration
}

func (m *MineKV) Open(fn string) {
	defer func() {
		go m.Duration()
	}()
	if fn == "" {
		fn = "default.cache"
	}
	m.cacheFile = fn

	bs, err := ioutil.ReadFile(fn)
	if err != nil {
		if !errors.Is(err, syscall.ERROR_FILE_NOT_FOUND) {
			panic(err)
		}

		fmt.Printf("创建缓存文件[%s]\n", fn)
		// 文件不存在, 创建缓存文件
		_, err = os.Create(m.cacheFile)
		if err != nil {
			panic(err)
		}
		return
	}

	if len(bs) == 0 {
		return
	}

	var ks []string
	err = json.Unmarshal(bs, &ks)
	if err != nil {
		panic(err)
	}
}

func (m *MineKV) Get(k string) string {
	m.rw.RLock()
	defer m.rw.RUnlock()

	return m.data[k]
}

func (m *MineKV) Set(k, v string) {
	m.rw.Lock()
	defer m.rw.Unlock()

	m.data[k] = v
}

// Duration 持久化数据至硬盘
func (m *MineKV) Duration() {
	for {
		time.Sleep(m.Ds)
		fmt.Println("进行数据持久化~")
		ks := make([]string, 0, len(m.data))
		for k := range m.data {
			ks = append(ks, k)
		}

		bs, err := json.Marshal(&ks)
		if err != nil {
			panic(err)
		}
		err = ioutil.WriteFile(m.cacheFile, bs, 0644)
		if err != nil {
			panic(err)
		}
	}
}
